package com.gpStudy.distributed.NIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NIOServerDemo {

    private int TIMEOUT = 3000;

    private int port ;

    private Selector selector ;

    private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    private ServerSocketChannel server;

    public NIOServerDemo(int port) {

        try {

            this.port = port;

            selector = Selector.open();

            server = ServerSocketChannel.open();

            server.bind(new InetSocketAddress(port));

            server.configureBlocking(false);

            server.register(selector, SelectionKey.OP_ACCEPT);

            while (true){

                if(selector.select(TIMEOUT) == 0){
                    System.out.println("==");
                    continue;
                }

                Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
                while(iter.hasNext()){
                    SelectionKey key = iter.next();

                    if(key.isAcceptable()){
                        handleAccept(key);
                    }
                    if(key.isReadable()){
                        handleRead(key);
                    }
                    if(key.isWritable() && key.isValid()){
                        handleWrite(key);
                    }
                    if(key.isConnectable()){
                        System.out.println("isConnectable = true");
                    }
                    iter.remove();
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            if (selector != null) {
                try {
                    selector.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (server != null) {
                try {
                    server.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    private void handleWrite(SelectionKey key) throws IOException {

        ByteBuffer buf = (ByteBuffer)key.attachment();// 附件，
        buf.flip();//读写指针移到缓存头部
        SocketChannel sc = (SocketChannel) key.channel();
        while(buf.hasRemaining()){
            sc.write(buf);
        }
        buf.compact();// 压缩
    }

    private void handleRead(SelectionKey key) throws IOException {

        SocketChannel sc = (SocketChannel)key.channel();
        ByteBuffer buf = (ByteBuffer)key.attachment();
        long bytesRead = sc.read(buf);
        while(bytesRead>0){
            buf.flip();
            while(buf.hasRemaining()){
                System.out.print((char)buf.get());
            }
            System.out.println();
            buf.clear();
            bytesRead = sc.read(buf);
        }
        if(bytesRead == -1){
            sc.close();
        }
    }

    /**
     * ServerSocketChannel 一直在监听端口，接收请求后就交给 一个sockeChanel 处理。
     * @param key
     * @throws IOException
     */
    private void handleAccept(SelectionKey key) throws IOException {

        ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();
        SocketChannel sc = ssChannel.accept();
        sc.configureBlocking(false);
        sc.register(key.selector(), SelectionKey.OP_READ, byteBuffer);
    }


}
